﻿#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <string.h>
/************************16.深入理解指针6****************************/
/*********1. sizeof和strlen的对⽐*********/
//1.sizeof是操作数，计算变量所占内存空间大小，单位是字节，sizeof只关注占⽤内存空间的⼤⼩，不在乎内存中存放什么数据。

//int main()
//{
//	/*int a = 10;
//	printf("%zd\n",sizeof(a));
//	printf("%zd\n", sizeof(int));*/
//
//	char arr[] = "abcdef";
//	//abcdef\0
//	printf("%zd\n", sizeof(arr)); //7
//	return 0;
//}

//2.strlen 是C语言库函数，功能是求字符串⻓度
//strlen统计的是从 strlen 函数的参数 str 中这个地址开始向后， \0 之前字符串中字符的个数。
//strlen 函数会⼀直向后找 \0 字符，直到找到为⽌，所以可能存在越界查找

//int main()
//{
//	//char arr[] = "abcdef";
//	//abcdef\0
//	//char arr[] = {'a','b','c'};
//	////abc
//
//	//printf("%zd\n", sizeof(arr)); //7 3
//	//printf("%zd\n", strlen(arr)); //6 随机值
//
//	//int arr[5] = { 0 };
//	//printf("%zd\n", sizeof(arr)); //20
//	//printf("%zd\n", strlen(arr)); //err
//
//	return 0;
//}

//数组名的理解
//数组名是数组首元素的地址
//但有2个例外
//1.sizeof(数组名)，数组名表示整个数组
//2.&数组名，数组名表示整个数组

//int main()
//{
//	int a[] = { 1,2,3,4 };
//	printf("%zd\n", sizeof(a));		  //16
//	printf("%zd\n", sizeof(a + 0));   //a最作为数组名，并未单独放在sizeof内部，a就是数组首元素地址
//	//a+0还是数组首元素的地址，sizeof(a+0)计算的是一个地址大小，4/8
//	printf("%zd\n", sizeof(*a));	  //a就是数组首元素地址，*a就是首元素，sizeof(*a)计算的就是数组首元素大小-4
//	printf("%zd\n", sizeof(a + 1));   //a就是数组首元素地址，a+1是数组第2个元素的地址，sizeof(a+1)计算的是一个地址大小，4/8
//	printf("%zd\n", sizeof(a[1]));    //sizeof(a[1])计算的是第二个元素的大小-4
//	printf("%zd\n", sizeof(&a));	  //&a取出的是整个数组的地址，一个地址大小，4/8
//	printf("%zd\n", sizeof(*&a));	  //数组的解引用访问整个数组，数组大小16
//	printf("%zd\n", sizeof(&a + 1));  //&a+1取出的是跳过整个数组的地址，一个地址大小，4/8
//	printf("%d\n", sizeof(&a[0]));	  //首元素地址，大小-4/8个字节
//	printf("%d\n", sizeof(&a[0] + 1));//第二个元素地址，大小-4/8个字节
//	return 0;
//}

//int main()
//{
//	char arr[] = { 'a','b','c','d','e','f' }; 
//
//	printf("%zd\n", sizeof(arr));		 //计算整个数组的大小-6
//	printf("%zd\n", sizeof(arr + 0));	 //arr+0是首元素的地址，4/8个字节
//	printf("%zd\n", sizeof(*arr));		 //*arr是首元素，1个字节
//	printf("%zd\n", sizeof(arr[1]));	 //1
//	printf("%zd\n", sizeof(&arr));		 //&arr是数组地址，是地址4/8
//	printf("%zd\n", sizeof(&arr + 1));	 //跳过整个数组后的地址，是地址4/8
//	printf("%zd\n", sizeof(&arr[0] + 1));//&arr[0]+1是第二个元素地址，4/8
//	return 0;
//}

//int main()
//{
//	char arr[] = { 'a','b','c','d','e','f' };
//	printf("%zd\n", strlen(arr));		 //随机值
//	printf("%zd\n", strlen(arr + 0));	 //随机值
//	printf("%zd\n", strlen(*arr));		 //*arr首元素- 'a' - 97strlen会把它当地址，野指针-err
//	printf("%zd\n", strlen(arr[1]));	 //'b' - 98 - err
//	printf("%zd\n", strlen(&arr));		 //随机值
//	printf("%zd\n", strlen(&arr + 1));	 //随机值
//	printf("%zd\n", strlen(&arr[0] + 1));//&arr[0] + 1是第二个元素的地址，随机值
//	return 0;
//}

//int main()
//{
//	char arr[] = "abcdef";
//	printf("%d\n", sizeof(arr));		//7
//	printf("%d\n", sizeof(arr + 0));	//arr+0是首元素的地址，4/8个字节
//	printf("%d\n", sizeof(*arr));		//*arr是首元素，1个字节
//	printf("%d\n", sizeof(arr[1]));		//第二个元素1
//	printf("%d\n", sizeof(&arr));		//数组的地址，4/8个字节
//	printf("%d\n", sizeof(&arr + 1));	//跳过数组后的地址，4/8个字节
//	printf("%d\n", sizeof(&arr[0] + 1));//第二个元素地址，4/8个字节
//
//	return 0;
//}

//int mian()
//{
//	char arr[] = "abcdef";
//	printf("%zd\n", strlen(arr));        //6
//	printf("%zd\n", strlen(arr + 0));	 //arr+0是首元素的地址，6
//	printf("%zd\n", strlen(*arr));		 //*arr是首元素,'a'-97-err
//	printf("%zd\n", strlen(arr[1]));	 //第二个元素,'b'-98-err
//	printf("%zd\n", strlen(&arr));		 //6
//	printf("%zd\n", strlen(&arr + 1));	 //跳过整个数组，随机值
//	printf("%zd\n", strlen(&arr[0] + 1));//第二个元素地址，5
//
//	return 0;
//}

//int mian()
//{
//	char* p = "abcdef";
//	printf("%zd\n", sizeof(p));        //指针变量，地址-4/8
//	printf("%zd\n", sizeof(p + 1));	   //跳一个字符，是第二个字符b的地址-4/8
//	printf("%zd\n", sizeof(*p));	   //*p访问第一个字符-1
//	printf("%zd\n", sizeof(p[0]));	   //p[0] = *(p+0)-1
//	printf("%zd\n", sizeof(&p));	   //数组的地址，4/8
//	printf("%zd\n", sizeof(&p + 1));   //跳过整个数组，还是地址，4/8
//	printf("%zd\n", sizeof(&p[0] + 1));//第二的字符的地址，4/8
//
//	return 0;
//}

//int mian()
//{
//	char* p = "abcdef";
//	printf("%zd\n", strlen(p));			//6
//	printf("%zd\n", strlen(p + 1));		//5
//	printf("%zd\n", strlen(*p));		//err
//	printf("%zd\n", strlen(p[0]));		//p[0] --*(p+0) - err
//	printf("%zd\n", strlen(&p));		//p的地址，随机值
//	printf("%zd\n", strlen(&p + 1));	//随机值
//	printf("%zd\n", strlen(&p[0] + 1)); //第二个元素的地址-5
//
//	return 0;
//}

//int main()
//{
//	int a[3][4] = { 0 };
//	printf("%zd\n", sizeof(a));			  //48 - a 单独放在sizeof里面，计算整个数组大小
//	printf("%zd\n", sizeof(a[0][0]));	  //4  - 第一行第一个元素
//	printf("%zd\n", sizeof(a[0]));		  //16 - a[0]作为第一行数组，计算整个数组大小
//	printf("%zd\n", sizeof(a[0] + 1));	  //
//	/*4/8 - 没有单独放在sizeof里面
//	a[0]就是首元素地址，
//	那就是&a[0][0],a[0]+1就是&a[0][1] ,
//	是地址
//	*/
//
//	printf("%zd\n", sizeof(*(a[0] + 1))); //4 - a[0]+1是a[0][1]的地址，*(a[0] + 1)就是a[0][1]元素的大小
//	printf("%zd\n", sizeof(a + 1));		  //4/8 - a是二维数组第一行的地址，a+1是第二行的地址
//	//a - int (*)[4]数组地址
//	//a + 1 - int (*)[4]
//	printf("%zd\n", sizeof(*(a + 1)));	  //16 - a+1是第二行的地址,*(a+1)就是第二行数组整个大小
//	printf("%zd\n", sizeof(&a[0] + 1));	  //4/8 - &a[0]是第一行的地址，加1取得是第二行的地址
//	printf("%zd\n", sizeof(*(&a[0] + 1)));//16 - &a[0] + 1是第二行的地址，*后计算的是第二行整个数组的大小
//	printf("%zd\n", sizeof(*a));		  //16 - a是二维数组第一行的地址，*a就是第一行，大小就是第一行整个数组
//	printf("%zd\n", sizeof(a[3]));		  //16 - a[3] 类似 a[2] a[1] a[0]
//	//sizeof在计算的时候是根据类型来计算长度的，即使写的是一个表达式，编译器也会推算最终类型，来计算长度
//
//	return 0;
//}

/***数组名的意义***/
//1. sizeof(数组名)，这⾥的数组名表⽰整个数组，计算的是整个数组的⼤⼩。
//2. & 数组名，这⾥的数组名表⽰整个数组，取出的是整个数组的地址。
//3. 除此之外所有的数组名都表⽰⾸元素的地址。


/***************指针笔试题***************/

//题目1.
//int main()
//{
//	int a[5] = { 1, 2, 3, 4, 5 };
//	//int (*)[5]
//	int* ptr = (int*)(&a + 1);
//	printf("%d,%d", *(a + 1), *(ptr - 1));//2，5
//	//a是首元素地址，加1是第二个元素地址，解引用是第二个元素2，ptr的地址是跳过整个数组的地址减1是最后一个元素。
//	return 0;
//}

//题目2.
//在X86环境下
//假设结构体的⼤⼩是20个字节
//程序输出的结果是啥？

//考察指针+1 就是地址+1，+1大小取决于指针类型的

//结构体指针类型
//struct Test
//{
//	int Num;
//	char* pcName;
//	short sDate;
//	char cha[2];
//	short sBa[4];
//}* p = (struct Test*)0x100000;//把0x100000强制类型转换成结构体指针
//
////0x开头的是16进制数字
//int main()
//{
//	printf("%p\n", p + 0x1);				//0x00100014，p是结构体指针类型，+1跳过一个结构体类型20，转换成16进制就是14，
//	printf("%p\n", (unsigned long)p + 0x1); //0x00100001，p强制类型转换成无符号长整型，不是指针+1，而是整数+1，所以就是直接+1
//	printf("%p\n", (unsigned int*)p + 0x1); //0x00100004，p强制类型转换成一个无符号整型 +1是跳过4个字节
//
//	return 0;
//}

//题目3
//int main()
//{
//	
//	//逗号表达式，所以会变成  { 1， 3， 5 }
//	int a[3][2] = { (0, 1), (2, 3), (4, 5) };//没用{}
//	int* p;
//	p = a[0]; //a[0]是第一行的数组名，表示首元素地址，&a[0][0]
//	printf("%d", p[0]);//1
//	 
//	return 0;
//}

//题目4
//假设环境是x86环境，程序输出的结果是啥？
//指针 减 指针，就是指针与指针之间元素的个数

//int main()
//{
//	int a[5][5];
//	int(*p)[4];//p是一个数组指针，这个指针指向的数组有4个int类型的元素
//	p = a;
//	printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);// -4 -4，
//					  //计算机存的是补码，地址打印出来也是补码					
//	return 0;
//}

//题目5
//int main()
//{
//	int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
//	int* ptr1 = (int*)(&aa + 1);
//	int* ptr2 = (int*)(*(aa + 1));
//	printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));//10  5
//
//	return 0;
//}

//题目6
//int main()
//{
//	char* a[] = { "work","at","alibaba" };
//	char** pa = a;
//	pa++;
//	printf("%s\n", *pa);//at
//
//	return 0;
//}

//题目7
//int main()
//{
//	char* c[] = { "ENTER","NEW","POINT","FIRST" };
//	char** cp[] = { c + 3,c + 2,c + 1,c };
//	char*** cpp = cp;
//	printf("%s\n", **++cpp);//++会改变值，POINT
//	printf("%s\n", *-- * ++cpp + 3);//ER
//	printf("%s\n", *cpp[-2] + 3);	//ST
//	printf("%s\n", cpp[-1][-1] + 1);//EW
//
//	return 0;
//}










































